Creating TumblrPublishAgent

Dean Putney 9 jaren geleden
bovenliggende
commit
b263b1c9f6

+ 3 - 0
.env.example

@@ -89,6 +89,9 @@ THIRTY_SEVEN_SIGNALS_OAUTH_SECRET=
89 89
 GITHUB_OAUTH_KEY=
90 90
 GITHUB_OAUTH_SECRET=
91 91
 
92
+TUMBLR_OAUTH_KEY=
93
+TUMBLR_OAUTH_SECRET=
94
+
92 95
 #############################
93 96
 #  AWS and Mechanical Turk  #
94 97
 #############################

+ 2 - 0
Gemfile

@@ -84,11 +84,13 @@ gem 'feed-normalizer'
84 84
 gem 'slack-notifier', '~> 0.5.0'
85 85
 gem 'therubyracer', '~> 0.12.1'
86 86
 gem 'mqtt'
87
+gem 'tumblr_client'
87 88
 
88 89
 gem 'omniauth'
89 90
 gem 'omniauth-twitter'
90 91
 gem 'omniauth-37signals'
91 92
 gem 'omniauth-github'
93
+gem 'omniauth-tumblr'
92 94
 
93 95
 group :development do
94 96
   gem 'binding_of_caller'

+ 11 - 0
Gemfile.lock

@@ -215,6 +215,8 @@ GEM
215 215
       multi_json (~> 1.3)
216 216
       oauth2 (~> 0.9.3)
217 217
       omniauth (~> 1.2)
218
+    omniauth-tumblr (1.1)
219
+      omniauth-oauth (~> 1.0)
218 220
     omniauth-twitter (1.0.1)
219 221
       multi_json (~> 1.3)
220 222
       omniauth-oauth (~> 1.0)
@@ -341,6 +343,13 @@ GEM
341 343
     treetop (1.4.15)
342 344
       polyglot
343 345
       polyglot (>= 0.3.1)
346
+    tumblr_client (0.8.4)
347
+      faraday (~> 0.9.0)
348
+      faraday_middleware (~> 0.9.0)
349
+      json
350
+      mime-types
351
+      oauth
352
+      simple_oauth
344 353
     twilio-ruby (3.11.6)
345 354
       builder (>= 2.1.2)
346 355
       jwt (>= 0.1.2)
@@ -429,6 +438,7 @@ DEPENDENCIES
429 438
   omniauth
430 439
   omniauth-37signals
431 440
   omniauth-github
441
+  omniauth-tumblr
432 442
   omniauth-twitter
433 443
   pg
434 444
   protected_attributes (~> 1.0.8)
@@ -452,6 +462,7 @@ DEPENDENCIES
452 462
   spring
453 463
   spring-commands-rspec
454 464
   therubyracer (~> 0.12.1)
465
+  tumblr_client
455 466
   twilio-ruby (~> 3.11.5)
456 467
   twitter (~> 5.8.0)
457 468
   typhoeus (~> 0.6.3)

+ 46 - 0
app/concerns/tumblr_concern.rb

@@ -0,0 +1,46 @@
1
+module TumblrConcern
2
+  extend ActiveSupport::Concern
3
+
4
+  included do
5
+    include Oauthable
6
+
7
+    validate :validate_tumblr_options
8
+    valid_oauth_providers :tumblr
9
+  end
10
+
11
+  def validate_tumblr_options
12
+    unless tumblr_consumer_key.present? &&
13
+      tumblr_consumer_secret.present? &&
14
+      tumblr_oauth_token.present? &&
15
+      tumblr_oauth_token_secret.present?
16
+      errors.add(:base, "Tumblr consumer_key, consumer_secret, oauth_token, and oauth_token_secret are required to authenticate with the Tumblr API.  You can provide these as options to this Agent, or as Credentials with the same names, but starting with 'tumblr_'.")
17
+    end
18
+  end
19
+
20
+  def tumblr_consumer_key
21
+    ENV['TUMBLR_OAUTH_KEY']
22
+  end
23
+
24
+  def tumblr_consumer_secret
25
+    ENV['TUMBLR_OAUTH_SECRET']
26
+  end
27
+
28
+  def tumblr_oauth_token
29
+    service.token
30
+  end
31
+
32
+  def tumblr_oauth_token_secret
33
+    service.secret
34
+  end
35
+
36
+  def tumblr
37
+    Tumblr.configure do |config|
38
+      config.consumer_key = tumblr_consumer_key
39
+      config.consumer_secret = tumblr_consumer_secret
40
+      config.oauth_token = tumblr_oauth_token
41
+      config.oauth_token_secret = tumblr_oauth_token_secret
42
+    end
43
+    
44
+    Tumblr::Client.new
45
+  end
46
+end

+ 9 - 0
app/controllers/application_controller.rb

@@ -40,4 +40,13 @@ class ApplicationController < ActionController::Base
40 40
       @basecamp_agent = current_user.agents.where(type: 'Agents::BasecampAgent').first
41 41
     end
42 42
   end
43
+
44
+  def tumblr_oauth_check
45
+    if ENV['TUMBLR_OAUTH_KEY'].blank? || ENV['TUMBLR_OAUTH_SECRET'].blank?
46
+      if @tumblr_agent = current_user.agents.where("type like 'Agents::Tumblr%'").first
47
+        @tumblr_oauth_key    = @tumblr_agent.options['consumer_key'].presence || @tumblr_agent.credential('tumblr_consumer_key')
48
+        @tumblr_oauth_secret = @tumblr_agent.options['consumer_secret'].presence || @tumblr_agent.credential('tumblr_consumer_secret')
49
+      end
50
+    end
51
+  end
43 52
 end

+ 164 - 0
app/models/agents/tumblr_publish_agent.rb

@@ -0,0 +1,164 @@
1
+require "tumblr_client"
2
+
3
+module Agents
4
+  class TumblrPublishAgent < Agent
5
+    include TumblrConcern
6
+
7
+    cannot_be_scheduled!
8
+
9
+    description <<-MD
10
+      The TumblrPublishAgent publishes Tumblr posts from the events it receives.
11
+
12
+To be able to use this Agent you need to authenticate with Tumblr in the [Services](/services) section first.
13
+
14
+
15
+
16
+**Required fields:**
17
+
18
+`blog_name` Your Tumblr URL (e.g. "mustardhamsters.tumblr.com") 
19
+
20
+`post_type` One of [text, photo, quote, link, chat, audio, video] 
21
+
22
+
23
+-------------
24
+
25
+You may leave any of the following optional fields blank. Including a field not allowed for the specified `post_type` will cause a failure.
26
+
27
+**Any post type**
28
+
29
+* `state` published, draft, queue, private
30
+* `tags` Comma-separated tags for this post
31
+* `tweet` off, text for tweet
32
+* `date` GMT date and time of the post as a string
33
+* `format` html, markdown
34
+* `slug` short text summary at end of the post URL
35
+
36
+**Text** `title` `body` 
37
+
38
+**Photo** `caption` `link`  `source`
39
+
40
+**Quote** `quote` `source`
41
+
42
+**Link** `title` `url` `description` 
43
+
44
+**Chat** `title` `conversation`
45
+
46
+**Audio** `caption` `external_url`
47
+
48
+**Video** `caption` `embed`
49
+
50
+
51
+-------------
52
+
53
+[Full information on field options](https://www.tumblr.com/docs/en/api/v2#posting)
54
+
55
+Set `expected_update_period_in_days` to the maximum amount of time that you'd expect to pass between Events being created by this Agent.
56
+    MD
57
+
58
+    def validate_options
59
+      errors.add(:base, "expected_update_period_in_days is required") unless options['expected_update_period_in_days'].present?
60
+    end
61
+
62
+    def working?
63
+      event_created_within?(interpolated['expected_update_period_in_days']) && most_recent_event && most_recent_event.payload['success'] == true && !recent_error_logs?
64
+    end
65
+
66
+    def default_options
67
+      {
68
+        'expected_update_period_in_days' => "10",
69
+        'blog_name' => "{{blog_name}}",
70
+        'post_type' => "{{post_type}}",
71
+        'options' => {
72
+          'state' => "{{state}}",
73
+          'tags' => "{{tags}}",
74
+          'tweet' => "{{tweet}}",
75
+          'date' => "{{date}}",
76
+          'format' => "{{format}}",
77
+          'slug' => "{{slug}}",
78
+          'title' => "{{title}}",
79
+          'body' => "{{body}}",
80
+          'caption' => "{{caption}}",
81
+          'link' => "{{link}}",
82
+          'source' => "{{source}}",
83
+          'quote' => "{{quote}}",
84
+          'url' => "{{url}}",
85
+          'description' => "{{description}}",
86
+          'conversation' => "{{conversation}}",
87
+          'external_url' => "{{external_url}}",
88
+          'embed' => "{{embed}}",
89
+        },
90
+      }
91
+    end
92
+
93
+    def receive(incoming_events)
94
+      # if there are too many, dump a bunch to avoid getting rate limited
95
+      if incoming_events.count > 20
96
+        incoming_events = incoming_events.first(20)
97
+      end
98
+      incoming_events.each do |event|
99
+        blog_name = interpolated(event)['blog_name']
100
+        post_type = interpolated(event)['post_type']
101
+        logger.error interpolated(event)
102
+        options = interpolated(event)['options']
103
+        begin
104
+          post = publish_post(blog_name, post_type, options)
105
+          puts "[POST] "+JSON.pretty_generate(post)
106
+          create_event :payload => {
107
+            'success' => true,
108
+            'published_post' => "["+blog_name+"] "+post_type,
109
+            'post_id' => post["id"],
110
+            'agent_id' => event.agent_id,
111
+            'event_id' => event.id
112
+          }
113
+        end
114
+      end
115
+    end
116
+
117
+    def publish_post(blog_name, post_type, options)
118
+      puts "[BLOG NAME] "+blog_name
119
+      puts "[POST_TYPE] "+post_type
120
+      
121
+      options_obj = { 
122
+          :state => options['state'],
123
+          :tags => options['tags'],
124
+          :tweet => options['tweet'],
125
+          :date => options['date'],
126
+          :format => options['format'],
127
+          :slug => options['slug'],
128
+        }
129
+
130
+      case post_type
131
+      when "text"
132
+        options_obj[:title] = options['title']
133
+        options_obj[:body] = options['body']
134
+        tumblr.text(blog_name, options_obj)
135
+      when "photo"
136
+        options_obj[:caption] = options['caption']
137
+        options_obj[:link] = options['link']
138
+        options_obj[:source] = options['source']
139
+        tumblr.photo(blog_name, options_obj)
140
+      when "quote"
141
+        options_obj[:quote] = options['quote']
142
+        options_obj[:source] = options['source']
143
+        tumblr.quote(blog_name, options_obj)
144
+      when "link"
145
+        options_obj[:title] = options['title']
146
+        options_obj[:url] = options['url']
147
+        options_obj[:description] = options['description']
148
+        tumblr.link(blog_name, options_obj)
149
+      when "chat"
150
+        options_obj[:title] = options['title']
151
+        options_obj[:conversation] = options['conversation']
152
+        tumblr.chat(blog_name, options_obj)
153
+      when "audio"
154
+        options_obj[:caption] = options['caption']
155
+        options_obj[:external_url] = options['external_url']
156
+        tumblr.audio(blog_name, options_obj)
157
+      when "video"
158
+        options_obj[:caption] = options['caption']
159
+        options_obj[:embed] = options['embed']
160
+        tumblr.video(blog_name, options_obj)
161
+      end
162
+    end
163
+  end
164
+end

+ 3 - 0
app/views/services/index.html.erb

@@ -20,6 +20,9 @@
20 20
       <% if has_oauth_configuration_for('github') %>
21 21
         <p><%= link_to "Authenticate with Github", "/auth/github" %></p>
22 22
       <% end -%>
23
+      <% if has_oauth_configuration_for('tumblr') %>
24
+        <p><%= link_to "Authenticate with Tumblr", "/auth/tumblr" %></p>
25
+      <% end -%>
23 26
       <hr>
24 27
 
25 28
       <div class='table-responsive'>

+ 1 - 0
config/initializers/omniauth.rb

@@ -2,4 +2,5 @@ Rails.application.config.middleware.use OmniAuth::Builder do
2 2
   provider :twitter, ENV['TWITTER_OAUTH_KEY'], ENV['TWITTER_OAUTH_SECRET'], authorize_params: {force_login: 'true', use_authorize: 'true'}
3 3
   provider '37signals', ENV['THIRTY_SEVEN_SIGNALS_OAUTH_KEY'], ENV['THIRTY_SEVEN_SIGNALS_OAUTH_SECRET']
4 4
   provider :github, ENV['GITHUB_OAUTH_KEY'], ENV['GITHUB_OAUTH_SECRET']
5
+  provider :tumblr, ENV['TUMBLR_OAUTH_KEY'], ENV['TUMBLR_OAUTH_SECRET']
5 6
 end

+ 24 - 27
db/schema.rb

@@ -11,14 +11,11 @@
11 11
 #
12 12
 # It's strongly recommended that you check this file into your version control system.
13 13
 
14
-ActiveRecord::Schema.define(version: 20140901143732) do
15
-
16
-  # These are extensions that must be enabled in order to support this database
17
-  enable_extension "plpgsql"
14
+ActiveRecord::Schema.define(version: 20140906030139) do
18 15
 
19 16
   create_table "agent_logs", force: true do |t|
20 17
     t.integer  "agent_id",                      null: false
21
-    t.text     "message",           limit: 16777215,             null: false, charset: "utf8mb4", collation: "utf8mb4_bin"
18
+    t.text     "message",                       null: false, charset: "utf8mb4", collation: "utf8mb4_bin"
22 19
     t.integer  "level",             default: 3, null: false
23 20
     t.integer  "inbound_event_id"
24 21
     t.integer  "outbound_event_id"
@@ -28,7 +25,7 @@ ActiveRecord::Schema.define(version: 20140901143732) do
28 25
 
29 26
   create_table "agents", force: true do |t|
30 27
     t.integer  "user_id"
31
-    t.text     "options",               limit: 16777215,                                charset: "utf8mb4", collation: "utf8mb4_bin"
28
+    t.text     "options",                                                               charset: "utf8mb4", collation: "utf8mb4_bin"
32 29
     t.string   "type",                                                                                      collation: "utf8_bin"
33 30
     t.string   "name",                                                                  charset: "utf8mb4", collation: "utf8mb4_bin"
34 31
     t.string   "schedule",                                                                                  collation: "utf8_bin"
@@ -36,17 +33,17 @@ ActiveRecord::Schema.define(version: 20140901143732) do
36 33
     t.datetime "last_check_at"
37 34
     t.datetime "last_receive_at"
38 35
     t.integer  "last_checked_event_id"
39
-    t.datetime "created_at",                                               null: false
40
-    t.datetime "updated_at",                                               null: false
36
+    t.datetime "created_at"
37
+    t.datetime "updated_at"
41 38
     t.text     "memory",                limit: 2147483647,                              charset: "utf8mb4", collation: "utf8mb4_bin"
42 39
     t.datetime "last_web_request_at"
43 40
     t.integer  "keep_events_for",                          default: 0,     null: false
44 41
     t.datetime "last_event_at"
45 42
     t.datetime "last_error_log_at"
46
-    t.boolean  "propagate_immediately", default: false, null: false
47
-    t.boolean  "disabled",              default: false, null: false
48
-    t.string   "guid",                                                     null: false, charset: "ascii",   collation: "ascii_bin"
43
+    t.boolean  "propagate_immediately",                    default: false, null: false
44
+    t.boolean  "disabled",                                 default: false, null: false
49 45
     t.integer  "service_id"
46
+    t.string   "guid",                                                     null: false
50 47
   end
51 48
 
52 49
   add_index "agents", ["guid"], name: "index_agents_on_guid", using: :btree
@@ -67,8 +64,8 @@ ActiveRecord::Schema.define(version: 20140901143732) do
67 64
   create_table "delayed_jobs", force: true do |t|
68 65
     t.integer  "priority",                    default: 0
69 66
     t.integer  "attempts",                    default: 0
70
-    t.text     "handler",    limit: 16777215,                          charset: "utf8mb4", collation: "utf8mb4_bin"
71
-    t.text     "last_error", limit: 16777215,                          charset: "utf8mb4", collation: "utf8mb4_bin"
67
+    t.text     "handler",    limit: 16777215,             charset: "utf8mb4", collation: "utf8mb4_bin"
68
+    t.text     "last_error",                              charset: "utf8mb4", collation: "utf8mb4_bin"
72 69
     t.datetime "run_at"
73 70
     t.datetime "locked_at"
74 71
     t.datetime "failed_at"
@@ -83,11 +80,11 @@ ActiveRecord::Schema.define(version: 20140901143732) do
83 80
   create_table "events", force: true do |t|
84 81
     t.integer  "user_id"
85 82
     t.integer  "agent_id"
86
-    t.decimal  "lat",                           precision: 15, scale: 10
87
-    t.decimal  "lng",                           precision: 15, scale: 10
88
-    t.text     "payload",    limit: 2147483647,                                        charset: "utf8mb4", collation: "utf8mb4_bin"
89
-    t.datetime "created_at",                                              null: false
90
-    t.datetime "updated_at",                                              null: false
83
+    t.decimal  "lat",                         precision: 15, scale: 10
84
+    t.decimal  "lng",                         precision: 15, scale: 10
85
+    t.text     "payload",    limit: 16777215,                           charset: "utf8mb4", collation: "utf8mb4_bin"
86
+    t.datetime "created_at"
87
+    t.datetime "updated_at"
91 88
     t.datetime "expires_at"
92 89
   end
93 90
 
@@ -117,13 +114,13 @@ ActiveRecord::Schema.define(version: 20140901143732) do
117 114
   add_index "scenario_memberships", ["scenario_id"], name: "index_scenario_memberships_on_scenario_id", using: :btree
118 115
 
119 116
   create_table "scenarios", force: true do |t|
120
-    t.string   "name",                        null: false, charset: "utf8mb4", collation: "utf8mb4_bin"
121
-    t.integer  "user_id",                     null: false
117
+    t.string   "name",                         null: false, charset: "utf8mb4", collation: "utf8mb4_bin"
118
+    t.integer  "user_id",                      null: false
122 119
     t.datetime "created_at"
123 120
     t.datetime "updated_at"
124
-    t.text     "description",                              charset: "utf8mb4", collation: "utf8mb4_bin"
125
-    t.boolean  "public",      default: false, null: false
126
-    t.string   "guid",                        null: false, charset: "ascii",   collation: "ascii_bin"
121
+    t.text     "description",                               charset: "utf8mb4", collation: "utf8mb4_bin"
122
+    t.boolean  "public",       default: false, null: false
123
+    t.string   "guid",                         null: false, charset: "ascii",   collation: "ascii_bin"
127 124
     t.string   "source_url"
128 125
     t.string   "tag_bg_color"
129 126
     t.string   "tag_fg_color"
@@ -154,8 +151,8 @@ ActiveRecord::Schema.define(version: 20140901143732) do
154 151
     t.integer  "user_id",                           null: false
155 152
     t.string   "credential_name",                   null: false
156 153
     t.text     "credential_value",                  null: false
157
-    t.datetime "created_at",                        null: false
158
-    t.datetime "updated_at",                        null: false
154
+    t.datetime "created_at"
155
+    t.datetime "updated_at"
159 156
     t.string   "mode",             default: "text", null: false, collation: "utf8_bin"
160 157
   end
161 158
 
@@ -172,8 +169,8 @@ ActiveRecord::Schema.define(version: 20140901143732) do
172 169
     t.datetime "last_sign_in_at"
173 170
     t.string   "current_sign_in_ip"
174 171
     t.string   "last_sign_in_ip"
175
-    t.datetime "created_at",                                         null: false
176
-    t.datetime "updated_at",                                         null: false
172
+    t.datetime "created_at"
173
+    t.datetime "updated_at"
177 174
     t.boolean  "admin",                              default: false, null: false
178 175
     t.integer  "failed_attempts",                    default: 0
179 176
     t.string   "unlock_token"